package com.tengju.user.infrastructure.shared;

import cn.hutool.core.util.ReflectUtil;
import com.tengju.user.domain.annotation.ElasticCryptEntity;
import com.tengju.user.domain.shared.AESUtil;
import com.tengju.user.domain.shared.CastUtil;
import com.tengju.user.domain.shared.Constant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Collection;

/**
 * @author: 李大仙
 * @date: 2021/8/30 5:52 下午
 */
@Slf4j
@Aspect
@Component
public class ElasticEncryptAction {

    @Pointcut("@annotation(com.tengju.user.domain.annotation.ElasticEncrypt)")
    private void elasticEncryptPointcut() {
    }

    @Around(value = "elasticEncryptPointcut()")
    public Object elasticEncryptAround(ProceedingJoinPoint pjp) {
        Object obj = null;
        Object[] args = pjp.getArgs();
        try {
            if (args != null && args.length > 0) {
                for (Object arg : args) {
                    encrypt(arg);
                }
            }
            obj = pjp.proceed();
        } catch (Throwable e) {
            log.error("es加密异常," + CastUtil.castString(obj),e);
        }
        return obj;
    }

    private void encrypt(Object arg) throws IllegalAccessException {
        if (arg == null) {
            return;
        }
        if (arg instanceof Collection) {
            for (Object obj : ((Collection<?>) arg)) {
                encrypt(obj);
            }
        }else if (arg instanceof Iterable) {
            for (Object obj : ((Iterable<?>) arg)) {
                encrypt(obj);
            }
        } else {
            encryptSingle(arg);
        }
    }

    private void encryptSingle(Object obj) throws IllegalAccessException {
        if (obj == null) {
            return ;
        }
        Class<?> clazz = obj.getClass();
        if (!clazz.isAnnotationPresent(ElasticCryptEntity.class)) {
            return;
        }
        ElasticCryptEntity cryptEntity = clazz.getAnnotation(ElasticCryptEntity.class);
        String[] cryptFieldNames = cryptEntity.cryptFields();
        if (cryptFieldNames.length == 0) {
            return;
        }
        for (String cryptFieldName : cryptFieldNames) {
            Field field = ReflectUtil.getField(clazz, cryptFieldName);
            if (field == null) {
                continue;
            }
            field.setAccessible(Boolean.TRUE);
            if (field.get(obj) == null) {
                continue;
            }
            Object val = field.get(obj);
            if (!(val instanceof String)) {
                log.info("es加密只支持字符串类型,{}",val);
                continue;
            }
            if (StringUtils.isBlank(val.toString())) {
                continue;
            }
            String encryptVal = AESUtil.encrypt(Constant.ELASTIC_ENCRYPT_KEY, val.toString());
            field.set(obj,encryptVal);
        }
    }


}
